package com.bee.base.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.bee.base.entity.Page;
import com.bee.base.util.CriteriaConstants;
import com.bee.base.util.GenericUtil;
import com.bee.base.util.HibernateQueryUtil;

@SuppressWarnings("rawtypes")
public class BaseDao<T> extends HibernateDaoSupport {

	protected Class entityClass;

	protected Class getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class clazz) {
		this.entityClass = clazz;
	}

	public BaseDao() {
		this.entityClass = GenericUtil.getGenericClass(getClass());
	}

	/**
	 * 新增实例
	 * 
	 * @param entity
	 * @return
	 */
	public Serializable save(T entity) {
		return super.getHibernateTemplate().save(entity);
	}

	/**
	 * 批量新增实例
	 * 
	 * @param entities
	 */
	public void saveAll(Collection<T> entities) {
		super.getHibernateTemplate().saveOrUpdateAll(entities);
	}

	/**
	 * 通过主键查询
	 * 
	 * @param sid
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T get(Long sid) {
		return (T) super.getHibernateTemplate().get(entityClass, sid);
	}

	/**
	 * 通过queryString查询
	 * 
	 * @param queryString
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(String queryString, Object... values) {
		return super.getHibernateTemplate().find(queryString, values);
	}

	/**
	 * 通过Example查询
	 * 
	 * @param entity
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(T entity) {
		return super.getHibernateTemplate().findByExample(entity);
	}

	/**
	 * 通过Criteria查询
	 * 
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> find(Map<String, String> params) {
		DetachedCriteria criteria = DetachedCriteria.forClass(entityClass);
		this.addCriterion(criteria, params);
		return super.getHibernateTemplate().findByCriteria(criteria);
	}

	/**
	 * 查询所有实例
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		return (List<T>) super.getHibernateTemplate().loadAll(entityClass);
	}

	/**
	 * 修改实例
	 * 
	 * @param entity
	 */
	public void update(T entity) {
		super.getHibernateTemplate().update(entity);
	}

	/**
	 * 批量修改实例
	 * 
	 * @param entities
	 */
	public void updateAll(Collection<T> entities) {
		super.getHibernateTemplate().saveOrUpdateAll(entities);
	}

	/**
	 * 删除实例
	 * 
	 * @param entity
	 */
	public void delete(T entity) {
		super.getHibernateTemplate().delete(entity);
	}

	/**
	 * 通过主键删除实例
	 * 
	 * @param sid
	 */
	public void delete(Long sid) {
		this.delete(this.get(sid));
	}

	/**
	 * 批量删除实例
	 * 
	 * @param entities
	 */
	public void deleteAll(Collection<T> entities) {
		super.getHibernateTemplate().deleteAll(entities);
	}

	/**
	 * 通过queryString分页
	 * 
	 * @param queryString
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public Page page(String queryString, int pageNo, int pageSize) {
		String countQueryString = "select count(*) " + queryString;
		int totalCount = (Integer) this.find(countQueryString).get(0);
		if (totalCount < 1) {
			return new Page();
		} else {
			int startIndex = Page.getStartOfPage(pageNo, pageSize);
			List results = super.getSession().createQuery(queryString).setFirstResult(startIndex)
					.setMaxResults(pageSize).list();
			return new Page(results, startIndex, pageSize, totalCount);
		}
	}

	/**
	 * 通过params分页
	 * 
	 * @param params
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public Page page(Map<String, String> params, int pageNo, int pageSize) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(entityClass);
		this.addCriterion(detachedCriteria, params);
		Criteria criteria = detachedCriteria.getExecutableCriteria(super.getSession());
		int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
		if (totalCount < 1) {
			return new Page();
		} else {
			criteria.setProjection(null);
			int startIndex = Page.getStartOfPage(pageNo, pageSize);
			List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
			return new Page(list, startIndex, pageSize, totalCount);
		}
	}

	/**
	 * 解析params
	 * 
	 * @param criteria
	 * @param params
	 */
	@SuppressWarnings("unchecked")
	protected void addCriterion(DetachedCriteria criteria, Map<String, String> params) {
		if (params != null && !params.isEmpty()) {
			HibernateQueryUtil.changeStringToClassFieldTypeOfMap(entityClass, params, true);
			for (String key : params.keySet()) {
				String type = key.split(CriteriaConstants.SPLIT)[0];
				String propertyName = key.split(CriteriaConstants.SPLIT)[1];
				Object value = params.get(key);
				if (type.equals(CriteriaConstants.EQ)) {
					criteria.add(Restrictions.eq(propertyName, value));
				} else if (type.equals(CriteriaConstants.NE)) {
					criteria.add(Restrictions.ne(propertyName, value));
				} else if (type.equals(CriteriaConstants.ALLEQ)) {
					criteria.add(Restrictions.allEq((Map) value));
				} else if (type.equals(CriteriaConstants.GT)) {
					criteria.add(Restrictions.gt(propertyName, value));
				} else if (type.equals(CriteriaConstants.GE)) {
					criteria.add(Restrictions.ge(propertyName, value));
				} else if (type.equals(CriteriaConstants.LT)) {
					criteria.add(Restrictions.lt(propertyName, value));
				} else if (type.equals(CriteriaConstants.LE)) {
					criteria.add(Restrictions.le(propertyName, value));
				} else if (type.equals(CriteriaConstants.BETWEEN)) {
					Map<String, Object> map = (Map<String, Object>) value;
					Object lo = map.get("lo");
					Object hi = map.get("hi");
					criteria.add(Restrictions.between(propertyName, lo, hi));
				} else if (type.equals(CriteriaConstants.LIKE)) {
					criteria.add(Restrictions.like(propertyName, (String) value, MatchMode.ANYWHERE));
				} else if (type.equals(CriteriaConstants.IN)) {
					criteria.add(Restrictions.in(propertyName, (Object[]) value));
				} else if (type.equals(CriteriaConstants.ISNULL)) {
					criteria.add(Restrictions.isNull(propertyName));
				} else if (type.equals(CriteriaConstants.ISNOTNULL)) {
					criteria.add(Restrictions.isNotNull(propertyName));
				} else if (type.equals(CriteriaConstants.ISEMPTY)) {
					criteria.add(Restrictions.isEmpty(propertyName));
				} else if (type.equals(CriteriaConstants.ISNOTEMPTY)) {
					criteria.add(Restrictions.isNotEmpty(propertyName));
				} else if (type.equals(CriteriaConstants.ASC)) {
					criteria.addOrder(Order.asc(propertyName));
				} else if (type.equals(CriteriaConstants.DESC)) {
					criteria.addOrder(Order.desc(propertyName));
				} else {
					criteria.add(Restrictions.eq(propertyName, value));
				}
			}
		}
	}

}
